var DEFAULT_LEAGUE_DUPLICATE_LEVEL_ID = 1;

function LeagueDuplicate() {
    this.idgen = 0,     // ID生成器
    this.leagues = {    // 军团副本信息
        /*
        'id' : {            //军团副本信息ID标识
            'max' : 0,          // 最高副本ID
            'cur' : 0,          // 当前副本ID
            'hp' : 0,           // 当前副本剩余血量
            'reset_time' : 0,   // 上次重置时间
            'score' : {         // 当前副本积分
                'uid' : 0,          // 角色ID的积分
            },

            'stat' : {          //统计信息
                'chapter' : {       // 章节ID
                    'uid' : {          // 角色ID
                        'rank' : 0,         // 排名
                        'score' : 0,        // 贡献积分
                        'award' : 0,       // 领奖标志
                    },
                }
            },
        }
        */
    },

    this.updates = {};
}

LeagueDuplicate.create = function() {
    var data = {
        _id:'league_duplicate',
        idgen:0,
        leagues:{},
    };

    gDBWorld.insert(data, function(err, result){});
}

LeagueDuplicate.prototype = {
    init : function(callback) {
        // 从数据库加载军团副本的数据
        gDBWorld.findOne({_id : 'league_duplicate'}, {}, function(err, doc) {
            if (doc) {
                this.idgen = doc.idgen;
                this.leagues = doc.leagues;
                this._init();
                callback && callback(true);
            } else {
                callback && callback(false);
            }
        }.bind(this));
    },

    _init : function() {
        for (var id in this.leagues) {
            this.leagues[id].id = id;
        }
    },

    update : function(duplicate, attr) {
        if (!duplicate || !duplicate.hasOwnProperty(attr)) {
            return;
        }
            
        this.updates[util.format('leagues.%d.%s', duplicate.id, attr)] = duplicate[attr];
    },

    save : function(force, callback) {
        if(!force && Object.keys(this.updates).length <= 10) {
            callback && callback(true);
            return;
        }
         
        var updates = this.updates;
        this.updates = {};

        gDBWorld.update({_id :'league_duplicate'}, {$set:updates}, function(err, result){
            if(err) {
                ERROR(util.format('SAVE LEAGUE_DUPLICATE: %j %j', updates, err));
                callback && callback(false);
            }else {
                LOG(util.format('SAVE LEAGUE_DUPLICATE: %j', updates));
                callback && callback(true);
            }
        });
    },
    
    // 通过信息ID获取军团副本信息
    get : function(id) {
        return this.leagues[id];
    },

    // 创建一条军团副本信息，返回信息ID
    add : function() {
        var duplicateConf = gConfLeagueDuplicate[DEFAULT_LEAGUE_DUPLICATE_LEVEL_ID];
        var id = ++this.idgen;
        var duplicate = {
            'id' : id,
            'max' : 0,
            'cur' : DEFAULT_LEAGUE_DUPLICATE_LEVEL_ID,
            'hp' : duplicateConf.TotalHP,
            'reset_time' : 0,
            'score' : {},
            'stat' : {},
        };

        this.updates['idgen'] = this.idgen;
        for (var attr in duplicate) {
            if (attr != 'id') {
                this.update(duplicate, attr);
            }
        }

        this.leagues[id] = duplicate;
        
        this.save(true);
        return id;
    },

    // 当上一关结束时跳转到下一关卡, 如果已经是最后一关，则返回false
    toNextLevel : function(league, duplicate) {
        if (duplicate.hp > 0) {
            return true;
        }

        var curDuplicateConf = gConfLeagueDuplicate[duplicate.cur];
        var curChapterId = curDuplicateConf.Battle;
        var nextDuplicateConf = gConfLeagueDuplicate[duplicate.cur + 1];
        
        if (duplicate.cur > duplicate.max) {
            duplicate.max = duplicate.cur;
            this.update(duplicate, 'max');
        }
        
        if (!nextDuplicateConf || nextDuplicateConf.Battle != curChapterId) {
            this.statChapterRank(duplicate, curChapterId);

            if (duplicate.cur > duplicate.max) {
                gMessage.addSystemMessage('league_duplicate_passed', [league.name, curDuplicateConf.Battle.toString(), curDuplicateConf.Chapter]);
            }

            if (!nextDuplicateConf) {
                return false;
            }
        }

        duplicate.cur += 1;
        duplicate.hp = nextDuplicateConf.TotalHP;
        this.update(duplicate, 'cur');
        this.update(duplicate, 'hp');
        return true;
    },

    // 统计章节排行
    statChapterRank : function(duplicate, chapterId) {
        if (duplicate.stat.hasOwnProperty(chapterId)) {
            return;
        }

        var scores = duplicate.score;
        var ranks = [];
        
        for (uid in scores) {
            ranks.push({'uid':uid, 'score':scores[uid]});
        }

        ranks.sort(function(a, b) {
            return b.score - a.score;
        });

        var chapterStat = {};
        for (var i = 0, max = ranks.length; i < max; ++i) {
            var rankInfo = ranks[i];
            chapterStat[rankInfo.uid] = {
                'rank': i + 1,
                'score' : rankInfo.score,
                'award' : 0,
            }
        }

        duplicate.score = {};
        duplicate.stat = {};
        duplicate.stat[chapterId] = chapterStat;
        
        this.update(duplicate, 'score');
        this.update(duplicate, 'stat');
    },

    // 移除成员，当玩家从军团退出时调用此接口清除其副本数据
    removeMember : function(duplicateId, uid) {
        var duplicate = this.leagues[duplicateId];
        if (!duplicate) {
            return;
        }

        if (duplicate.score[uid]) {
            delete duplicate.score[uid];
            this.update(duplicate, 'score');
        }

        for (var chapter in duplicate.stat) {
            var chapterStat = duplicate.stat[chapter];
            if (chapterStat[uid]) {
                delete chapterStat[uid];
                this.update(duplicate, 'stat');
                break;
            }
        }
    },

    getAwardType : function(rank) {
        if (rank <= 1) {
            return 'diamond';
        } else if (rank <= 2) {
            return 'platinum';
        } else if (rank <= 3) {
            return 'gold';
        } else if (rank <= 10) {
            return 'silver';
        } else {
            return 'bronze';
        }
    }
};

exports.refresh = function(req, resp, onHandled) {
    var uid = req.uid;

    do {
        var league = gLeague.getUserLeague(uid);
        if (!league) {
            resp.code = 3; resp.desc = 'not in league'; break;
        }

        var duplicate = gLeague.getLeagueDuplicate(league);
        if (!duplicate) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        gLeagueDuplicate.toNextLevel(league, duplicate);
        
        var respGot = {};
        for (cid in duplicate.stat) {
            var chapterStat = duplicate.stat[cid];
            respGot[cid] = (!chapterStat[uid]) ? -1 : chapterStat[uid].award;
        }

        resp.data.league_duplicate = {
            'duplicate' : {
                'max' : duplicate.max,
                'id' : duplicate.cur,
                'hp' : duplicate.hp,
            },

            'update_time' : duplicate.reset_time,
            'got' : respGot,
        }

    } while (false);

    onHandled && onHandled();
}

exports.attack = function(req, resp, onHandled) {
    var uid = req.uid;

    do {
        var league = gLeague.getUserLeague(uid);
        if (!league) {
            resp.code = 3; resp.desc = 'not in league'; break;
        }

        var duplicate = gLeague.getLeagueDuplicate(league);
        if (!duplicate) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var oldHealth = duplicate.hp;
        if (oldHealth <= 0 && !gLeagueDuplicate.toNextLevel(league, duplicate)) {
            resp.code = 0; resp.desc = 'passed all'; break;
        }

        var duplicateConf = gConfLeagueDuplicate[duplicate.cur];
        if (!duplicateConf) {
            resp.code = 1; resp.desc = 'invalid conf'; break;
        }

        if (req.args.level < duplicateConf.LevelLimit) {
            resp.code = 1; resp.desc = 'level limit'; break;
        }

        var costFood = duplicateConf.IsBoss ? +gConfGlobal.LeagueDuplicateBossFood : +gConfGlobal.LeagueDuplicateFood;
        if (req.args.food < costFood) {
            resp.code = 1; resp.desc = 'food not enough'; break;
        }

        var inspire = req.args.inspire;
        var oldLevelId = duplicate.cur;

        var monsterHealth = Math.max(1, Math.floor(duplicate.hp/duplicateConf.TotalMonster));
        fightLeagueDuplicate(uid, inspire, duplicateConf, monsterHealth, function(battleReport) {
            if (!battleReport) {
                resp.code = 1; resp.desc = 'battle error'; return;
            }

            var defRemainInfo = battleReport.def_remain_info;
            var nowHealth = 0;
            for (var rid in defRemainInfo) {
                nowHealth += defRemainInfo[rid].health;
            }

            if (nowHealth < duplicateConf.TotalMonster) {
                nowHealth = 0;
            }

            duplicate.hp = nowHealth;
            gLeagueDuplicate.update(duplicate, 'hp');

            var addHonor = 0;
            var hurt = oldHealth - nowHealth;
            if (hurt > 0) {
                addHonor = Math.floor(Math.min(Math.max(0.1, hurt/duplicateConf.TotalHP), 0.12) * duplicateConf.Honor);
                duplicate.score[uid] = hurt + (duplicate.score[uid] || 0);
                gLeagueDuplicate.update(duplicate, 'score');
            }
            
            if (nowHealth <= 0) {
                gLeagueDuplicate.toNextLevel(league, duplicate);
            }

            gLeagueDuplicate.save();

            resp.data.battle = battleReport;
            resp.data.attack_id = oldLevelId;
            resp.data.food = -costFood;
            resp.data.glory = addHonor;
            resp.data.id = duplicate.cur;
            resp.data.hp = duplicate.hp;
        });
    } while (false);

    onHandled && onHandled();
}

exports.award = function(req, resp, onHandled) {
    var uid = req.uid;

    do {
        if (isNaN(req.args.id)) {
            resp.code = 1; resp.desc = 'invalid arg id'; break;            
        }

        var league = gLeague.getUserLeague(uid);
        if (!league) {
            resp.code = 3; resp.desc = 'not in league'; break;
        }

        var duplicate = gLeague.getLeagueDuplicate(league);
        if (!duplicate) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var chapterId = parseInt(req.args.id);
        var stat = duplicate.stat[chapterId];
        if (!stat) {
            resp.code = 1; resp.desc = 'chapter not passed'; break;
        }

        var userRank = stat[uid];
        if (!userRank) {
            resp.code = 1; resp.desc = 'not in rank'; break;
        }

        if (userRank.award > 0) {
            resp.code = 1; resp.desc = 'awarded'; break;
        }

        userRank.award = 1;
        gLeagueDuplicate.update(duplicate, 'stat');
        gLeagueDuplicate.save();

        resp.data.type = gLeagueDuplicate.getAwardType(userRank.rank);
    } while (false);

    onHandled && onHandled();
}

exports.reset = function(req, resp, onHandled) {
    var uid = req.uid;

    do {
        var league = gLeague.getUserLeague(uid);
        if (!league) {
            resp.code = 3; resp.desc = 'not in league'; break;
        }

        var duplicate = gLeague.getLeagueDuplicate(league);
        if (!duplicate) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        if (!gLeague.isLeagueLeader(league, uid)) {
            resp.code = 1; resp.desc = 'not leader'; break;
        }

        var nowTime = common.getTime();
        var needCash = 0;

        if (duplicate.reset_time && (nowTime - duplicate.reset_time < +gConfGlobal.LeagueDuplicateResetInterval*3600)) {
            needCash = +gConfGlobal.LeagueDuplicateResetCash;
            if (req.args.cash < needCash) {
                resp.code = 1; resp.desc = 'cash not enough'; break;
            }
        }

        var duplicateConf = gConfLeagueDuplicate[DEFAULT_LEAGUE_DUPLICATE_LEVEL_ID];
        
        duplicate.cur = DEFAULT_LEAGUE_DUPLICATE_LEVEL_ID;
        duplicate.hp = duplicateConf.TotalHP;
        duplicate.reset_time = nowTime;
        duplicate.score = {};
        duplicate.stat = {};
       
        var duplicateId = duplicate.id;
        gLeagueDuplicate.update(duplicate, 'cur');
        gLeagueDuplicate.update(duplicate, 'hp');
        gLeagueDuplicate.update(duplicate, 'reset_time');
        gLeagueDuplicate.update(duplicate, 'score');
        gLeagueDuplicate.update(duplicate, 'stat');
        gLeagueDuplicate.save();

        resp.data.cash = needCash;
        resp.data.league_duplicate = {
            'duplicate' : {
                'max' : duplicate.max,
                'id' : duplicate.cur,
                'hp' : duplicate.hp,
            },

            'update_time' : duplicate.reset_time,
            'got' : {},
        }
    } while (false);

    onHandled && onHandled();
}

exports.get_rank = function(req, resp, onHandled) {
    var uid = req.uid;

    do {
        if (isNaN(req.args.id)) {
            resp.code = 3; resp.desc = 'invalid arg id'; break;    
        }

        var league = gLeague.getUserLeague(uid);
        if (!league) {
            resp.code = 3; resp.desc = 'not in league'; break;
        }

        var duplicate = gLeague.getLeagueDuplicate(league);
        if (!duplicate) {
            resp.code = 1; resp.desc = 'not open'; break;
        }


        var chapterId = +req.args.id;
        var curDuplicateConf = gConfLeagueDuplicate[duplicate.cur];
        var ranks = [];

        var chapterStat = duplicate.stat[chapterId];
        if (chapterStat) {
            for (var id in chapterStat) {
                var userInfo = gUserInfo.getUser(id);
                if (userInfo) {
                    var userRank = chapterStat[id];
                    ranks.push({'uid':id, 'name':userInfo.name, 'score':userRank.score, 'rank':userRank.rank});
                }
            }
        } else if (chapterId == curDuplicateConf.Battle) {
            var scores = duplicate.score;
            for (var id in scores) {
                var userInfo = gUserInfo.getUser(id);
                if (userInfo) {
                    ranks.push({'uid':id, 'name':userInfo.name, 'score':scores[id], 'rank':0});
                }
            }
        } else {
            resp.code = 1; resp.desc = 'invalid chapter'; break;
        }

        var respGot = {};
        for (cid in duplicate.stat) {
            var stat = duplicate.stat[cid];
            respGot[cid] = (!stat[uid]) ? -1 : stat[uid].award;
        }

        resp.data.rank = ranks;
        resp.data.got = respGot;
    } while (false);

    onHandled && onHandled();
}

exports.LeagueDuplicate = LeagueDuplicate;
